package com.loooooo.cas.web.session;

import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.annotation.Nullable;
import javax.servlet.ServletContext;
import javax.servlet.http.*;
import java.io.Serializable;
import java.util.*;

public class MyHttpSession implements HttpSession, Serializable {
    public static final long serialVersionUID = 1L;

    private static int nextId = 1;
    private String id;
    private final long creationTime;
    private int maxInactiveInterval;
    private long lastAccessedTime;
    private final ServletContext servletContext;
    private final Map<String, Object> attributes;
    private boolean invalid;
    private boolean isNew;

    public MyHttpSession(String id) {
        this((ServletContext) null);
        this.id = id;
    }

    public MyHttpSession() {
        this((ServletContext) null);
    }

    public MyHttpSession(@Nullable ServletContext servletContext) {
        this(servletContext, (String) null);
    }

    public MyHttpSession(@Nullable ServletContext servletContext, @Nullable String id) {
        this.creationTime = System.currentTimeMillis();
        this.lastAccessedTime = System.currentTimeMillis();
        this.attributes = new LinkedHashMap();
        this.invalid = false;
        this.isNew = true;
        this.servletContext = null;
        this.id = id != null ? id : Integer.toString(nextId++);
    }

    public long getCreationTime() {
        this.assertIsValid();
        return this.creationTime;
    }

    public String getId() {
        return this.id;
    }

    public String changeSessionId() {
        this.id = Integer.toString(nextId++);
        return this.id;
    }

    public void access() {
        this.lastAccessedTime = System.currentTimeMillis();
        this.isNew = false;
    }

    public long getLastAccessedTime() {
        this.assertIsValid();
        return this.lastAccessedTime;
    }

    public ServletContext getServletContext() {
        return this.servletContext;
    }

    public void setMaxInactiveInterval(int interval) {
        this.maxInactiveInterval = interval;
    }

    public int getMaxInactiveInterval() {
        return this.maxInactiveInterval;
    }

    public HttpSessionContext getSessionContext() {
        throw new UnsupportedOperationException("getSessionContext");
    }

    public Object getAttribute(String name) {
//        this.assertIsValid();
//        Assert.notNull(name, "Attribute name must not be null");
        return this.attributes.get(name);
    }

    public Object getValue(String name) {
        return this.getAttribute(name);
    }

    public Enumeration<String> getAttributeNames() {
        this.assertIsValid();
        return Collections.enumeration(new LinkedHashSet(this.attributes.keySet()));
    }

    public String[] getValueNames() {
        this.assertIsValid();
        return StringUtils.toStringArray(this.attributes.keySet());
    }

    public void setAttribute(String name, @Nullable Object value) {
        //this.assertIsValid();
        //Assert.notNull(name, "Attribute name must not be null");
        if (value != null) {
            Object oldValue = this.attributes.put(name, value);
            if (value != oldValue) {
                if (oldValue instanceof HttpSessionBindingListener) {
                    ((HttpSessionBindingListener) oldValue).valueUnbound(new HttpSessionBindingEvent(this, name, oldValue));
                }

                if (value instanceof HttpSessionBindingListener) {
                    ((HttpSessionBindingListener) value).valueBound(new HttpSessionBindingEvent(this, name, value));
                }
            }
        } else {
            this.removeAttribute(name);
        }

    }

    public void putValue(String name, Object value) {
        this.setAttribute(name, value);
    }

    public void removeAttribute(String name) {
        this.assertIsValid();
        //Assert.notNull(name, "Attribute name must not be null");
        Object value = this.attributes.remove(name);
        if (value instanceof HttpSessionBindingListener) {
            ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value));
        }

    }

    public void removeValue(String name) {
        this.removeAttribute(name);
    }

    public void clearAttributes() {
        Iterator it = this.attributes.entrySet().iterator();

        while (it.hasNext()) {
            Map.Entry<String, Object> entry = (Map.Entry) it.next();
            String name = (String) entry.getKey();
            Object value = entry.getValue();
            it.remove();
            if (value instanceof HttpSessionBindingListener) {
                ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value));
            }
        }

    }

    public void invalidate() {
        this.assertIsValid();
        this.invalid = true;
        this.clearAttributes();
    }

    public boolean isInvalid() {
        return this.invalid;
    }

    private void assertIsValid() {
        //Assert.state(!this.isInvalid(), "The session has already been invalidated");
    }

    public void setNew(boolean value) {
        this.isNew = value;
    }

    public boolean isNew() {
        this.assertIsValid();
        return this.isNew;
    }

    public Serializable serializeState() {
        HashMap<String, Serializable> state = new HashMap();
        Iterator it = this.attributes.entrySet().iterator();

        while (it.hasNext()) {
            Map.Entry<String, Object> entry = (Map.Entry) it.next();
            String name = (String) entry.getKey();
            Object value = entry.getValue();
            it.remove();
            if (value instanceof Serializable) {
                state.put(name, (Serializable) value);
            } else if (value instanceof HttpSessionBindingListener) {
                ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value));
            }
        }

        return state;
    }

    public void deserializeState(Serializable state) {
        //Assert.isTrue(state instanceof Map, "Serialized state needs to be of type [java.util.Map]");
        this.attributes.putAll((Map) state);
    }

    public static String getCookieName() {
        return "JSCard2023";
    }
}
